/*

   Copyright 2009 BBC Research, David Lewis, <david.lewis4@bbc.co.uk>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

 */
package MessageHandler;

import java.sql.Connection;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import javax.swing.JOptionPane;


public class DBLoggerGPS extends Thread {

    /**
     * Main part of logger,
     */
    @Override
    public void run() {

        //Create recieving space for packet
        byte[] bytePacket = new byte[128];
        DatagramPacket packet = new DatagramPacket(bytePacket, bytePacket.length);

        //Loop to keep recieving
        while (socketOpen() && Thread.interrupted()) {

            //Try and recieve packet
            try {
                socket.receive(packet);
                bytePacket = packet.getData();

                //process message
                processMessage(bytePacket);

                //error handling
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(Admin.getFrames()[0], "Socket error", ex.getMessage(), JOptionPane.WARNING_MESSAGE);
                java.util.logging.Logger.getLogger(DBLoggerGPS.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Extract useful data from the raw packet
     * @param bytePacket Bytes from raw packet
     */
    private void processMessage(byte[] bytePacket) {

        String message = new String(bytePacket, 0, bytePacket.length);
        System.out.println(message);
        String[] parts = message.split(",");

        //If this is a start up message and device has not been seen, add it
        if (parts[0].equals("running")) {
            //devices.put(parts[1], new Device());
            //If this device is checking in without a position note it
        } else if (parts[0].equals("check")) {
            //devices.get(parts[1]).setLastSeen();
            //If this is a location update, store it
        } else if (parts[0].equals("location")) {
       
        //Extract coordinates and important info
        double x = Double.valueOf(parts[2]);
        double y = Double.valueOf(parts[3]);
        double z = Double.valueOf(parts[4]);

        float error = Float.valueOf(parts[5])*Float.valueOf(parts[6]);

        double time = System.currentTimeMillis();

        long tag = Long.valueOf(parts[1]);

        //Send appropriately rounded results to DB
        toDB((float) tag, Math.round(Math.round(x)), Math.round(Math.round(y)), Math.round(Math.round(z)), Math.round(Math.round(time)), error);
        }

    }

    /**
     * Add the recieved data to the appropriate event table in the database
     * @param tag Tag ID
     * @param x   Coordinate
     * @param y   Coordinate
     * @param z   Coordinate
     * @param time Timecode (ms since midnight)
     * @param error Error distance
     */
    private void toDB(float tag, float x, float y, float z, int time, float error) {
        try {

            Statement st = dbc.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); //Set up DB query

            ResultSet rs = st.executeQuery("insert into " + table + "(tag,x,y,z,tc) values("
                    + tag + "," + x + "," + y + "," + z + "," + time + ")"); // Execute insert

            
            //Return coordinates to the gui to display in the list
            gui.addMessage(time + " tag:" + tag + " ,X:" + x + ", Y:" + y + ", Z:" + z);

            //Error handling
        } catch (SQLException ex) {
            JOptionPane.showMessageDialog(Admin.getFrames()[0], "SQL error", ex.getMessage(), JOptionPane.WARNING_MESSAGE);
            java.util.logging.Logger.getLogger(DBLoggerGPS.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Constructor for the logging thread
     * @param port  Port to listen for Ubisense UDP packets
     * @param dbc   Database connection
     * @param table Table to use
     * @param gui
     */
    public DBLoggerGPS(int port, Connection dbc, String table, Admin gui) {
        this.table = table;
        this.dbc = dbc;
        this.gui = gui;

        try {
            //Connect socket
            socket = new DatagramSocket(port);

            //Error handling
        } catch (SocketException ex) {
            JOptionPane.showMessageDialog(Admin.getFrames()[0], "Socket error", ex.getMessage(), JOptionPane.WARNING_MESSAGE);
            java.util.logging.Logger.getLogger(DBLoggerGPS.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * Indicates if this thread has a socket open
     * @return If the socket is open
     */
    public boolean socketOpen() {
        return socket.isConnected();
    }
    private DatagramSocket socket;
    private char locationMessageHex = 0x26a;
    private Connection dbc;
    private String table;
    private Admin gui;
}
